﻿#region References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using LuaInterface;
using System.Reflection;
using Ness.Engine.GUI;
using Microsoft.Xna.Framework;
#endregion

namespace Ness.Engine.Lua
{
    /// <summary>
    /// Allows parsing of Lua scripts for the engine
    /// </summary>
    class LuaParser : LuaInterface.Lua
    {
        #region Private variables
        private LuaEngineProxy engineProxy;
        private LuaMapProxy mapProxy;
        #endregion

        /// <summary>
        /// Converts a LuaTable to a Vector3
        /// </summary>
        /// <param name="tbl">The LuaTable to convert</param>
        /// <returns></returns>
        public static Vector3 tableToVector(LuaTable tbl)
        {
            double[] vec = new double[tbl.Values.Count];
            tbl.Values.CopyTo(vec, 0);
            return new Vector3((float)vec[0], (float)vec[1], (float)vec[2]);
        }

        /// <summary>
        /// Initialises the parser and loads in default scripts
        /// </summary>
        /// <param name="game">The current engine instance</param>
        public LuaParser(Engine game)
        {
            try
            {
                //Set the engine "proxy"
                engineProxy = new LuaEngineProxy(this, game);

                //Set the map "proxy"
                mapProxy = new LuaMapProxy(this, game);

                //Set default global variables
                this["game"] = "Beckis Sandbox";
                this["engine"] = game;

                //Register default lua functions
                this.RegisterFunction("print", this, this.GetType().GetMethod("PrintLua"));

                //Default engine specific functions
                registerLuaFunctions(engineProxy);
                registerLuaFunctions(mapProxy);

                //Get lua scripts in scripts/default and execute them
                DirectoryInfo di = new DirectoryInfo("scripts/default");
                FileInfo[] rgFiles = di.GetFiles("*.lua");
                foreach (FileInfo fi in rgFiles)
                {
                    Debugger.WriteLua("Loading file: " + "scripts/default/" + fi.Name);
                    DoFile("scripts/default/" + fi.Name);
                }

                //Show init message
                Debugger.WriteLua("Lua Initiated. Game: " + game.ToString());
            }
            catch (Exception e)
            {
                Debugger.WriteError("Unable to init lua: " + e.Message);
            }
        }

        /// <summary>
        /// Registers public void functions for Lua to use
        /// </summary>
        /// <param name="pTarget">The class to register from</param>
        public void registerLuaFunctions(Object pTarget)
        {
            Type pTrgType = pTarget.GetType();

            foreach (MethodInfo mInfo in pTrgType.GetMethods())
            {
                if (mInfo.IsPublic)
                {
                    String strFName = mInfo.Name;
                    Debugger.WriteLua("Registered method: " + pTarget.GetType().ToString() + "." + strFName);
                    this.RegisterFunction(strFName, pTarget, mInfo);
                }
            }
        }

        /// <summary>
        /// Allows parsing of single files
        /// </summary>
        /// <param name="fileName">The file name/url</param>
        public new void DoFile(string fileName)
        {
            try
            {
                base.DoFile(fileName);
            }
            catch(Exception e)
            {
                Debugger.WriteError("Lua Error: " + e.Message);
            }
        }

        /// <summary>
        /// Prints a Lua string to the debugger
        /// </summary>
        /// <param name="str">The string to print</param>
        public void PrintLua(string str)
        {
            Debugger.WriteLua("Lua output: " + str);
        }
    }
}
